package com.yunxin.yundubbo.codecs;

import com.yunxin.yundubbo.mode.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import io.netty.handler.codec.CodecException;

import java.util.List;

public class MessageCodecs extends ByteToMessageCodec<Message> {

    private static final int MIN_FRAME_LENGTH = 10;

    private static final int MAX_FRAME_LENGTH=102400;

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, Message message, ByteBuf byteBuf) throws Exception {

        //设置版本号
        byteBuf.writeShort(message.getVersion());
        //设置魔法数字
        byteBuf.writeShort(message.getMagic());
        //设置业务类型
        byteBuf.writeShort(message.getType());
        //设置数据长度
        byteBuf.writeInt(message.getBytes().length);
        //设置数据
        byteBuf.writeBytes(message.getBytes());
    }

    @Override
    protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf in, List<Object> list) throws Exception {
        if (in.readableBytes() < MIN_FRAME_LENGTH) {
            return;
        }
        // 标记当前读取位置，以便回滚
        in.markReaderIndex();
        try {
            // 读取协议头
            short version = in.readShort();
            short magic = in.readShort();
            short type = in.readShort();
            int length = in.readInt();
            // 验证数据长度
            if (length < 0 || length > MAX_FRAME_LENGTH) {
                throw new CodecException("Invalid data length: " + length);
            }
            // 检查是否有足够的数据可读
            if (in.readableBytes() < length) {
                in.resetReaderIndex(); // 数据不足，重置读取位置
                return;
            }
            // 读取数据
            byte[] data = new byte[length];
            in.readBytes(data);
            // 构建消息对象
            Message message = new Message();
            message.setVersion(version);
            message.setMagic(magic);
            message.setType(type);
            message.setLength(length);
            message.setBytes(data);
            list.add(message);
        } catch (Exception e) {
            channelHandlerContext.fireExceptionCaught(new CodecException("Failed to decode message", e));
        }
    }
}
